﻿using System;
using System.Collections;
using System.Collections.Generic;
using CalcSharp.Core;
using CalcSharp.Core.Containers;
using CalcSharp.Core.Plugin;

namespace plug_roman
{
    enum RomanDigit
    {
        I = 1,
        V = 5,
        X = 10,
        L = 50,
        C = 100,
        D = 500,
        M = 1000
    }

    public class Roman2num: ICMDPlugin
    {
        private IPluginHost host;

        public Tresult Run(ArrayList parameters)
        {
            Tresult res = new Tresult();
            res.floatingpt = 0;

            string roman = Convert.ToString(parameters[0]).ToUpper().Trim();
            if (roman == "N") return res;

            if (roman.Split('V').Length > 2 || roman.Split('L').Length > 2 || roman.Split('D').Length > 2) throw new CSException("Not a Roman number acording to rule #4");

            int count = 1;
            char last = 'Z';

            foreach (char numeral in roman)
            {
                if ("IVXLCDM".IndexOf(numeral) == -1) throw new CSException("Invalid char: " + numeral);
                if (numeral == last)
                {
                    count++;
                    if (count == 4) throw new CSException("Not a Roman number acording to rule #1");
                }
                else
                {
                    count = 1;
                    last = numeral;
                }
            }

            int ptr = 0;
            List<double> values = new List<double>();
            int maxDigit = 1000;
            while (ptr < roman.Length)
            {
                // Base value of digit
                char numeral = roman[ptr];
                int digit = (int)Enum.Parse(typeof(RomanDigit), numeral.ToString());

                // Rule 3
                if (digit > maxDigit) throw new CSException("Not a Roman number acording to rule #3");

                // Next digit
                int nextDigit = 0;
                if (ptr < roman.Length - 1)
                {
                    char nextNumeral = roman[ptr + 1];
                    nextDigit = (int)Enum.Parse(typeof(RomanDigit), nextNumeral.ToString());

                    if (nextDigit > digit)
                    {
                        if ("IXC".IndexOf(numeral) == -1 || nextDigit > (digit * 10) || roman.Split(numeral).Length > 3) throw new CSException("Not a Roman number acording to rule #3");
                        maxDigit = digit - 1;
                        digit = nextDigit - digit;
                        ptr++;
                    }
                }
                values.Add(digit);
                ptr++;
            }
            for (int i = 0; i < values.Count - 1; i++)
            {
                if ((int)values[i] < (int)values[i + 1]) throw new  CSException("Not a Roman number acording to rule #3");
            }

            foreach (double d in values) res.floatingpt += d;

            return res;
        }

        public string Name
        {
            get { return "ROMAN2NUM"; }
        }

        public Dictionary<string, string> autocomplete
        {
            get { return null; }
        }

        public string Help
        {
            get { return Properties.Resources.roman2num; }
        }

        public IPluginHost Host
        {
            get
            {
                return this.host;
            }
            set
            {
                this.host = value;
                this.host.Register(this);
            }
        }
    }
}
